//SPDX-FileCopyrightText: Copyright 2025-2025 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package fs_api_serv

import (
	"context"
	"fmt"
	"io"
	"time"

	"atomgit.com/openlinksaas-org/extension-proto-gen-go.git/extension_fs_api"
	"gitcode.com/eteam/api-server/dao"
	"gitcode.com/eteam/api-server/dao/fs_dao"
	"gitcode.com/eteam/api-server/utils"
	"gitcode.com/eteam/proto-gen-go.git/fs_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

type FsApiImpl struct {
	fs_api.UnimplementedFsApiServer
	fsPermCheck *_FsPermCheck
	remoteAddr  string
}

func NewProjectFsApiImpl(remoteAddr string) *FsApiImpl {
	return &FsApiImpl{remoteAddr: remoteAddr, fsPermCheck: &_FsPermCheck{}}
}

func (apiImpl *FsApiImpl) StatFile(ctx context.Context, req *fs_api.StatFileRequest) (*fs_api.StatFileResponse, error) {
	emptyFileInfo := &fs_api.FileInfo{}

	_, adminOk := dao.CacheDao.GetAdminSession(ctx, req.SessionId)
	var userId = ""
	if !adminOk {
		sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
		if !ok {
			return &fs_api.StatFileResponse{
				Code:     fs_api.StatFileResponse_CODE_WRONG_SESSION,
				ErrMsg:   "会话不存在",
				FileInfo: emptyFileInfo,
			}, nil
		}
		userId = sessionItem.UserId
	}

	fsItem, err := fs_dao.FsInfoDao.Get(ctx, req.FsId)
	if err != nil {
		return &fs_api.StatFileResponse{
			Code:     fs_api.StatFileResponse_CODE_NO_FS,
			ErrMsg:   "文件存储不存在",
			FileInfo: emptyFileInfo,
		}, nil
	}
	fileItem, err := fs_dao.FsFileDao.Get(ctx, req.FsId, req.FileId)
	if err != nil {
		return &fs_api.StatFileResponse{
			Code:     fs_api.StatFileResponse_CODE_NO_FILE,
			ErrMsg:   "文件不存在",
			FileInfo: emptyFileInfo,
		}, nil
	}
	if !adminOk {
		allow, err := apiImpl.fsPermCheck.CheckAllowRead(ctx, userId, fsItem, fileItem)
		if err != nil {
			return nil, err
		}
		if !allow {
			return &fs_api.StatFileResponse{
				Code:     fs_api.StatFileResponse_CODE_NO_PERMISSION,
				ErrMsg:   "没有权限",
				FileInfo: emptyFileInfo,
			}, nil
		}
	}

	return &fs_api.StatFileResponse{
		Code:     fs_api.StatFileResponse_CODE_OK,
		FileInfo: fileItem.ToFileInfo(),
	}, nil
}

func (apiImpl *FsApiImpl) ReadFile(req *fs_api.ReadFileRequest, s fs_api.FsApi_ReadFileServer) error {
	ctx := s.Context()

	_, adminOk := dao.CacheDao.GetAdminSession(ctx, req.SessionId)
	var userId = ""
	if !adminOk {
		sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
		if !ok {
			return s.Send(&fs_api.ReadFileResponse{
				Code:   fs_api.ReadFileResponse_CODE_WRONG_SESSION,
				ErrMsg: "会话不存在",
			})
		}
		userId = sessionItem.UserId
	}

	fsItem, err := fs_dao.FsInfoDao.Get(ctx, req.FsId)
	if err != nil {
		return s.Send(&fs_api.ReadFileResponse{
			Code:   fs_api.ReadFileResponse_CODE_NO_FS,
			ErrMsg: "文件存储不存在",
			Data:   []byte{},
		})
	}
	fileItem, err := fs_dao.FsFileDao.Get(ctx, req.FsId, req.FileId)
	if err != nil {
		return s.Send(&fs_api.ReadFileResponse{
			Code:   fs_api.ReadFileResponse_CODE_NO_FILE,
			ErrMsg: "文件不存在",
			Data:   []byte{},
		})
	}
	if !adminOk {
		allow, err := apiImpl.fsPermCheck.CheckAllowRead(ctx, userId, fsItem, fileItem)
		if err != nil {
			return err
		}
		if !allow {
			return s.Send(&fs_api.ReadFileResponse{
				Code:   fs_api.ReadFileResponse_CODE_NO_PERMISSION,
				ErrMsg: "没有权限",
				Data:   []byte{},
			})
		}
	}
	if apiImpl.remoteAddr == "" {
		return s.Send(&fs_api.ReadFileResponse{
			Code:   fs_api.ReadFileResponse_CODE_NO_STORAGE_SERVER,
			ErrMsg: "未配置存储服务",
			Data:   []byte{},
		})
	}
	conn, err := utils.ConnGrpc(apiImpl.remoteAddr)
	if err != nil {
		return err
	}
	defer conn.Close()

	client := extension_fs_api.NewExtensionFsApiClient(conn)
	rs, err := client.ReadFile(ctx, &extension_fs_api.ReadFileRequest{
		FsId:   fileItem.FsId,
		FileId: fileItem.FileId,
	})
	if err != nil {
		return err
	}
	for {
		res, err := rs.Recv()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
		s.Send(&fs_api.ReadFileResponse{
			Code: fs_api.ReadFileResponse_CODE_OK,
			Data: res.Data,
		})
	}
	return nil
}

func (apiImpl *FsApiImpl) WriteFile(s fs_api.FsApi_WriteFileServer) error {
	ctx := s.Context()

	fsId := ""
	fileName := ""
	fileId := uuid.NewString()
	var fileSize uint32
	createUserId := ""

	if apiImpl.remoteAddr == "" {
		return s.SendAndClose(&fs_api.WriteFileResponse{
			Code:   fs_api.WriteFileResponse_CODE_NO_STORAGE_SERVER,
			ErrMsg: "未配置存储服务",
		})
	}
	conn, err := utils.ConnGrpc(apiImpl.remoteAddr)
	if err != nil {
		return err
	}
	defer conn.Close()

	client := extension_fs_api.NewExtensionFsApiClient(conn)
	rs, err := client.WriteFile(s.Context())
	if err != nil {
		return err
	}
	for {
		req, err := s.Recv()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
		// lastReq = req
		if createUserId == "" { //first req
			_, adminOk := dao.CacheDao.GetAdminSession(ctx, req.SessionId)
			var userId = "__ADMIN__"
			if !adminOk {
				sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
				if !ok {
					return s.SendAndClose(&fs_api.WriteFileResponse{
						Code:   fs_api.WriteFileResponse_CODE_WRONG_SESSION,
						ErrMsg: "会话不存在",
					})
				}
				userId = sessionItem.UserId
			}
			fsId = req.FsId
			fileName = req.FileName
			fsItem, err := fs_dao.FsInfoDao.Get(ctx, req.FsId)
			if err != nil {
				return s.SendAndClose(&fs_api.WriteFileResponse{
					Code:   fs_api.WriteFileResponse_CODE_NO_FS,
					ErrMsg: "文件存储不存在",
				})
			}
			if !adminOk {
				allow, err := apiImpl.fsPermCheck.CheckAllowWrite(ctx, userId, fsItem, req.FsId)
				if err != nil {
					return err
				}
				if !allow {
					return s.SendAndClose(&fs_api.WriteFileResponse{
						Code:   fs_api.WriteFileResponse_CODE_NO_PERMISSION,
						ErrMsg: "没有权限",
					})
				}
			}
			createUserId = userId
			if fsItem.MaxTotalSize > 0 && fsItem.Status.TotalFileSize > fsItem.MaxTotalSize {
				return s.SendAndClose(&fs_api.WriteFileResponse{
					Code:   fs_api.WriteFileResponse_CODE_NO_PERMISSION,
					ErrMsg: "超过存储上限",
				})
			}
		}
		err = rs.Send(&extension_fs_api.WriteFileRequest{
			FsId:   req.FsId,
			FileId: fileId,
			Data:   req.Data,
		})
		if err != nil {
			return err
		}
		fileSize += uint32(len(req.Data))
	}
	_, err = rs.CloseAndRecv()
	if err != nil {
		return err
	}

	//写入数据库
	err = apiImpl.AddFileInDb(ctx, fsId, fileId, fileName, fileSize, createUserId)
	if err != nil {
		return err
	}
	return s.SendAndClose(&fs_api.WriteFileResponse{
		Code:   fs_api.WriteFileResponse_CODE_OK,
		FileId: fileId,
	})
}

func (apiImpl *FsApiImpl) AddFileInDb(ctx context.Context, fsId, fileId, fileName string, fileSize uint32, createUserId string) error {
	//更新数据库
	dbSess, err := dao.StartSession()
	if err != nil {
		return err
	}
	defer dao.EndSession(dbSess)
	_, err = dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err := fs_dao.FsFileDao.Insert(sessCtx, &fs_dao.FileInfoDbItem{
			FileId:       fileId,
			FileName:     fileName,
			FsId:         fsId,
			FileSize:     fileSize,
			CreateTime:   time.Now().UnixNano() / 1e6,
			CreateUserId: createUserId,
			OwnerType:    fs_api.FILE_OWNER_TYPE_FILE_OWNER_TYPE_NONE,
			OwnerId:      "",
		})
		if err != nil {
			fmt.Println(err)
			return nil, err
		}
		err = fs_dao.FsInfoDao.IncStatus(sessCtx, fsId, 1, int64(fileSize))
		if err != nil {
			fmt.Println(err)
			return nil, err
		}
		return nil, nil
	})
	return err
}

func (apiImpl *FsApiImpl) SetFileOwner(ctx context.Context, req *fs_api.SetFileOwnerRequest) (*fs_api.SetFileOwnerResponse, error) {
	_, adminOk := dao.CacheDao.GetAdminSession(ctx, req.SessionId)
	var userId = ""
	if !adminOk {
		sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
		if !ok {
			return &fs_api.SetFileOwnerResponse{
				Code:   fs_api.SetFileOwnerResponse_CODE_WRONG_SESSION,
				ErrMsg: "会话不存在",
			}, nil
		}
		userId = sessionItem.UserId
	}

	fsItem, err := fs_dao.FsInfoDao.Get(ctx, req.FsId)
	if err != nil {
		return &fs_api.SetFileOwnerResponse{
			Code:   fs_api.SetFileOwnerResponse_CODE_NO_FS,
			ErrMsg: "文件存储不存在",
		}, nil
	}
	fileItem, err := fs_dao.FsFileDao.Get(ctx, req.FsId, req.FileId)
	if err != nil {
		return &fs_api.SetFileOwnerResponse{
			Code:   fs_api.SetFileOwnerResponse_CODE_NO_FILE,
			ErrMsg: "文件不存在",
		}, nil
	}
	if !adminOk {
		allow, err := apiImpl.fsPermCheck.CheckAllowSetOwner(ctx, userId, fsItem, fileItem, req.OwnerType, req.OwnerId)
		if err != nil {
			return nil, err
		}
		if !allow {
			return &fs_api.SetFileOwnerResponse{
				Code:   fs_api.SetFileOwnerResponse_CODE_NO_PERMISSION,
				ErrMsg: "没有权限",
			}, nil
		}
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)
	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = fs_dao.FsFileDao.SetOwner(sessCtx, req.FsId, req.FileId, int32(req.OwnerType), req.OwnerId)
		if err != nil {
			return nil, err
		}
		return &fs_api.SetFileOwnerResponse{
			Code: fs_api.SetFileOwnerResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*fs_api.SetFileOwnerResponse), nil
}

func (apiImpl *FsApiImpl) GetFsStatus(ctx context.Context, req *fs_api.GetFsStatusRequest) (*fs_api.GetFsStatusResponse, error) {
	emptyFsStatus := &fs_api.FsStatus{}
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &fs_api.GetFsStatusResponse{
			Code:     fs_api.GetFsStatusResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			FsStatus: emptyFsStatus,
		}, nil
	}
	fsItem, err := fs_dao.FsInfoDao.Get(ctx, req.FsId)
	if err != nil {
		return &fs_api.GetFsStatusResponse{
			Code:     fs_api.GetFsStatusResponse_CODE_NO_FS,
			ErrMsg:   "文件存储不存在",
			FsStatus: emptyFsStatus,
		}, nil
	}
	allow, err := apiImpl.fsPermCheck.CheckAllowStatFs(ctx, sessionItem.UserId, fsItem)
	if err != nil {
		return nil, err
	}
	if !allow {
		return &fs_api.GetFsStatusResponse{
			Code:     fs_api.GetFsStatusResponse_CODE_NO_PERMISSION,
			ErrMsg:   "没有权限",
			FsStatus: emptyFsStatus,
		}, nil
	}
	return &fs_api.GetFsStatusResponse{
		Code:     fs_api.GetFsStatusResponse_CODE_OK,
		FsStatus: fsItem.ToFsStatus(),
	}, nil
}
